package com.vhuomai.product.service.impl;

import com.quanyue.auto.util.AssertUtils;
import com.quanyue.auto.util.CollectionUtils;
import com.quanyue.auto.util.GlobalContext;
import com.vhuomai.mybatis.mapper.concurrent.MapperFuture;
import com.vhuomai.mybatis.mapper.page.Page;
import com.vhuomai.mybatis.mapper.page.PageRequest;
import com.vhuomai.product.constant.ProductStatus;
import com.vhuomai.product.dto.*;
import com.vhuomai.product.entity.*;
import com.vhuomai.product.label.entity.BaseLabel;
import com.vhuomai.product.label.entity.BaseProductLabel;
import com.vhuomai.product.label.mapper.LabelMapper;
import com.vhuomai.product.label.mapper.LabelProductMapper;
import com.vhuomai.product.mapper.ProductMapper;
import com.vhuomai.product.mapper.ProductValueMapper;
import com.vhuomai.product.mapper.SkuMapper;
import com.vhuomai.product.mapper.SlideImageMapper;
import com.vhuomai.product.service.ProductService;
import com.vhuomai.product.service.SpuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author harris
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductValueMapper productValueMapper;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private SpuService spuService;
    @Autowired
    private SlideImageMapper slideImageMapper;
    @Autowired
    private LabelProductMapper labelProductMapper;
    @Autowired
    private LabelMapper labelMapper;

    @Override
    public Page <BaseProduct> findProducts(PageRequest request) {
        return productMapper.findByMerchantNo(GlobalContext.merchantNo(), request);
    }

    @Override
    public List <BaseProduct> findHomeProducts() {
        return productMapper.findHomeProduct(GlobalContext.merchantNo(), true);
    }

    @Override
    public ProductBasic findBaseById(int productId) {
        ProductBasic productBasic = productMapper.findBaseOne(productId);
        if (productBasic == null) {
            return null;
        }
        BaseProductLabel baseProductLabel = labelProductMapper.findByProduct(productId);
        if (baseProductLabel != null) {
            BaseLabel baseLabel = labelMapper.findOne(baseProductLabel.getLabelId());
            productBasic.setProductLabelId(baseLabel.getId());
            productBasic.setProductLabelName(baseLabel.getName());
        }
        productBasic.setSlideImages(slideImageMapper.findByProductId(productId));
        return productBasic;
    }

    @Override
    public BaseProduct findSimpleById(int productId) {
        return productMapper.findSimpleById(productId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseProduct addProduct(ProductBasic product) {
        product.setMerchantNo(GlobalContext.merchantNo());
        product.setCreateTime(LocalDateTime.now());
        product.setUpdateTime(product.getCreateTime());
        product.setStatus(ProductStatus.SOLD_OUT);
        productMapper.insert(product);
        if (CollectionUtils.isNotEmpty(product.getSlideImages())) {
            this.insertSlideImages(product.getId(), product.getSlideImages());
        }
        return product;
    }

    @Override
    public void updateProduct(ProductBasic product) {
        product.setUpdateTime(LocalDateTime.now());
        productMapper.updateSelective(product);
        if (CollectionUtils.isNotEmpty(product.getSlideImages())) {
            slideImageMapper.deleteByProductId(product.getId());
            this.insertSlideImages(product.getId(), product.getSlideImages());
        }
    }

    @Override
    public void removeProduct(int productId) {
        BaseProduct baseProduct = new BaseProduct();
        baseProduct.setId(productId);
        baseProduct.setStatus(ProductStatus.DELETED);
        productMapper.updateSelective(baseProduct);
    }

    @Override
    public List <SpuItemEdit> findSpuValues(int productId) {
        BaseProduct baseProduct = productMapper.findOne(productId);
        AssertUtils.notNull(baseProduct, "商品不存在");
        MapperFuture <List <BaseProductValue>> baseProductValuesFuture = productValueMapper.findByProductIdAsync(productId);
        List <SpuItem> spuItems = spuService.findItemsBySpuId(baseProduct.getSpuId());
        Map <Integer, String> itemValueMap = baseProductValuesFuture
            .get()
            .stream()
            .collect(Collectors.toMap(BaseProductValue::getSpuItemId, BaseProductValue::getItemValue));
        List <SpuItemEdit> spuEditItems = new ArrayList <>(spuItems.size());
        for (SpuItem spuItem : spuItems) {
            if (!spuItem.getSku()) {
                SpuItemEdit itemEdit = new SpuItemEdit();
                itemEdit.setId(spuItem.getId());
                itemEdit.setItemName(spuItem.getName());
                itemEdit.setRequired(spuItem.getRequired());
                itemEdit.setItemType(spuItem.getItemType());
                itemEdit.setValue(itemValueMap.getOrDefault(spuItem.getId(), ""));
                itemEdit.setOptions(spuItem.getOptions());
                spuEditItems.add(itemEdit);
            }
        }
        return spuEditItems;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpuValues(int productId, Map <Integer, String> valuesMap) {
        BaseProduct baseProduct = productMapper.findOne(productId);
        AssertUtils.notNull(baseProduct, "商品不存在");
        valuesMap.remove(-1);
        List <BaseSpuItem> spuItems = spuService.findBaseItemBySpuId(baseProduct.getSpuId());
        List <BaseProductValue> values = new ArrayList <>(valuesMap.size());
        for (BaseSpuItem spuItem : spuItems) {
            String value = valuesMap.get(spuItem.getId());
            if (spuItem.getRequired()) {
                AssertUtils.notBlank(value, spuItem.getName() + "是必填项");
            }
            AssertUtils.isTrue(spuItem.getItemType().validator().validate(value), spuItem.getName() + "格式有误");
            BaseProductValue productValue = new BaseProductValue();
            productValue.setSpuItemId(spuItem.getId());
            productValue.setProductId(productId);
            productValue.setItemValue(value);
            productValue.setCreateTime(LocalDateTime.now());
            productValue.setUpdateTime(productValue.getCreateTime());
            values.add(productValue);
        }
        productValueMapper.deleteByProductId(productId);
        productValueMapper.insertAll(values);
    }

    @Override
    public ProductSku findSku(int productId) {
        BaseProduct baseProduct = productMapper.findOne(productId);
        AssertUtils.notNull(baseProduct, "商品不存在");
        MapperFuture <List <BaseSku>> baseSkuListFuture = skuMapper.findByProductIdAsync(productId);
        List <SpuItem> spuItems = spuService.findItemsBySpuId(baseProduct.getSpuId());
        ProductSku productSku = new ProductSku();
        productSku.setSkuList(baseSkuListFuture.get());
        List <SkuItem> skuItems = new ArrayList <>(3);
        for (SpuItem spuItem : spuItems) {
            if (spuItem.getSku()) {
                SkuItem skuItem = new SkuItem();
                skuItem.setId(spuItem.getId());
                skuItem.setName(spuItem.getName());
                skuItem.setOptions(spuItem.getOptions());
                skuItem.setItemType(spuItem.getItemType());
                skuItem.setRequired(spuItem.getRequired());
                skuItems.add(skuItem);
            }
        }
        productSku.setItems(skuItems);
        return productSku;
    }

    @Override
    public void updateSku(BaseSku sku) {
        sku.setUpdateTime(LocalDateTime.now());
        skuMapper.updateSelective(sku);
    }

    private void insertSlideImages(int productId, List <BaseSlideImage> images) {
        if (CollectionUtils.isEmpty(images)) {
            return;
        }
        for (BaseSlideImage baseSlideImage : images) {
            baseSlideImage.setId(null);
            baseSlideImage.setProductId(productId);
            baseSlideImage.setCreateTime(LocalDateTime.now());
            baseSlideImage.setUpdateTime(baseSlideImage.getCreateTime());
        }
        slideImageMapper.insertAll(images);
    }
}
